package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/google/uuid"

	"github.com/spf13/cast"

	"gitee.com/clearluo/gotools/util"
	"gitee.com/clearluo/gotools/zaplog"
)

var (
	httpClient http.Client
)

func init() {
	t := http.DefaultTransport.(*http.Transport).Clone()
	t.MaxIdleConnsPerHost = 100
	//t.TLSHandshakeTimeout = 3 * time.Second
	httpClient = http.Client{
		Timeout: 16 * time.Second,

		Transport: t,
	}
}
func main() {
	go util.MonitorStatus(time.Minute)
	fmt.Println("Client Test ... start")
	clientNum := 100
	times := 300
	if len(os.Args) != 3 {
		fmt.Println("./xxx.exe ip:port num/second")
		return
	}
	addr := os.Args[1]
	clientNum = cast.ToInt(os.Args[2])
	reqURL := fmt.Sprintf("http://%v/pingPost", addr)
	for j := 0; j < times; j++ {
		go func(j int) {
			succ := int64(0)
			fail := int64(0)
			w := &sync.WaitGroup{}
			w.Add(clientNum)
			start := time.Now()
			for i := 0; i < clientNum; i++ {
				go func(i int) {
					client(reqURL, w, i, &succ, &fail)
				}(i)
			}
			w.Wait()
			zaplog.Infof("第%vs,成功:%v,失败:%v 耗时:%v", j, succ, fail, time.Since(start))
		}(j)
		time.Sleep(time.Second)
	}
	select {}
	fmt.Println("Client Test ... End")

}

type ReqDataT struct {
	Id string `json:"id"`
}

func client(addr string, w *sync.WaitGroup, cilentID int, succ *int64, fail *int64) (err error) {
	defer func() {
		if err != nil {
			atomic.AddInt64(fail, 1)
		} else {
			atomic.AddInt64(succ, 1)
		}
		w.Done()
	}()
	reqData := ReqDataT{Id: uuid.NewString()}
	req, err := http.NewRequest("POST", addr, strings.NewReader(util.AssertMarshal(reqData)))
	if err != nil {
		return err
	}
	resp, err := httpClient.Do(req)
	if err != nil {
		//log.Fatal(err)
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		err = fmt.Errorf("statusCode:%v", resp.StatusCode)
		return err
	}
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		//log.Fatal(err)
		return err
	}
	respData := ReqDataT{}
	if err = json.Unmarshal(b, &respData); err != nil {
		return err
	}
	if respData.Id != reqData.Id {
		err = fmt.Errorf("reqId!=respID,%v,%v", reqData.Id, respData.Id)
		zaplog.Warn(err)
		return err
	}
	return nil
}
